// 变量声明 var const let

// 布尔值
let isDone: boolean = false

// 数字
let decLiteral: number = 6

// 字符串
let name2: string = "bob"

// 数组
let list: number[] = [1, 2, 3]
let list2: Array<String> = ['1', '2', '3']

// 元组
let x: [string, number] = ['hello', 10]
// 枚举 经测试：里面的值暂只能是number和string类型、若是为number类型，例如Blue=3，则可通过:string = Color[3]获取枚举名
enum Color { Red = '1', Green = '2', Blue = 3, yellow = 4, pink = '5' }
let c: Color = Color.Green
let colorName: string = Color[3]

// Any 动态类型
let notSure: any = 4
notSure = "maybe a string instead"
notSure = false
// 使用数组时，元素是不同类型的
notSure = [1, 2, '3', { a: 1 }]

// Void
function warnUser(): void {
    console.log("This is my warning message")
}

// Null 和 Undefined
let u1: number = undefined
let n1: number = null

// Never
// 返回never的函数必须存在无法达到的终点、后续代码不执行（例如error、死循环等）

function error(message: string): never {
    throw new Error(message)
}
function fail() {
    return error("Something failed")
}

function infiniteLoop(): never {
    while (true) {

    }
}

// 对象
let o: object = { a: 1, b: 2, c: 3, d: [{ da: 1 }, 2], e: { ea: 1, eb: 2 } }

// 函数
function add(x: number, y?: number): number {
    return x + y
}

let myAdd = function (x: string = '3', ...y: string[]): string {
    return x + ' ' + y.join(' ')
}


// 泛型
function identity<T>(arg: T): T {
    return arg
}

const output = identity<string>("myString")


// 高级类型
// 交叉类型
function extend<T, U>(first: T, second: U): T & U {
    let result = <T & U>{}
    for (let id in first) {
        (<any>result)[id] = (<any>first)[id]
    }
    for (let id in second) {
        if (!result.hasOwnProperty(id)) {
            (<any>result)[id] = (<any>second)[id]
        }
    }
    return result
}

class Person {
    constructor(public name: string) { }
}
interface Loggable {
    log(): void
}
class ConsoleLogger implements Loggable {
    log() {
        console.log(this)
    }
}
const jim = extend(new Person("Jim"), new ConsoleLogger())
const n = jim.name
jim.log()
const a = extend('1', false)

// 联合类型
function padLeft(value: string, padding: string | number): object {
    const result: object = { value, padding }
    return result
}

const indentedString = padLeft("Hello world", 1)


// Symbols
// 对象属性
const sym = Symbol('key')
const obj: object = {
    [sym]: "value"
}
console.log(obj[sym])

// 类成员属性
const getClassNameSymbol = Symbol()
class C {
    // Symbol成员属性
    [getClassNameSymbol](): string {
        return "C1d"
    }
    // symbols列表
    [Symbol.hasInstance](instance): Boolean {
        console.log('instance:', instance)
        return Array.isArray(instance)
    }
    [Symbol.search](string: string): number {
        console.log('string:', string)
        return 1
    }
}
const class1 = new C()
const className = class1[getClassNameSymbol]
const className1 = className()
console.log('className1:', className1)
console.log('Symbol.hasInstance:', [] instanceof <any>new C)
console.log('Symbol.search:', 'C2112'.search(<any>class1))




// 接口
// 对象类型
interface SquareConfig {
    color?: string
    ary?: number[]
    width: number
    height: number
    readonly getArea: Function
}
const s1: SquareConfig = { width: 1, height: 2, ary: [1, 2], getArea: function (): number { return s1.width * s1.height } }
s1.width = 32
console.log(s1)
console.log(s1.getArea())

// 函数类型
interface SearchFunc {
    (source: string, subString: string): boolean
}
let mySearch: SearchFunc
mySearch = function (source, subString) {
    let result = source.search(subString)
    return result > -1
}
console.log(mySearch('aabbccdd', 'c'))

// 类类型
interface ClockInterface {
    currentTime: Date
    setTime(d: Date)
}

class Clock implements ClockInterface {
    currentTime: Date
    setTime(d: Date) {
        this.currentTime = d
    }
    getTime() {
        return this.currentTime
    }
    constructor(currentTime: Date) {
        this.currentTime = currentTime
    }
}

const Clock1 = new Clock(new Date('2020-06-30'))
console.log(Clock1.getTime())

// 接口相互继承
interface Shape {
    color: string
}
interface Square extends Shape {
    sideLength: number
}
const square: Square = { color: 'blue', sideLength: 10 }

// 接口继承类
interface ClockInterfaceExtend extends Clock {
    select(): void
}
const Clock2 = <ClockInterfaceExtend>{ currentTime: new Date('2019-05-28'), setTime: () => { }, getTime: () => { return Clock2.currentTime }, select: () => { } }
console.log(Clock2.getTime())



// 类
class Greeter {
    // 公共，私有与受保护的修饰符
    public greeting: string
    private color: string
    protected timer: Date
    // 构造函数
    constructor(message: string) {
        this.greeting = message
    }
    greet() {
        return "Hello, " + this.greeting
    }
    getColor() {
        return this.color
    }
    setColor(color: string) {
        this.color = color
    }
}

// 继承
class Greeter2 extends Greeter {
    private greeting2: string
    // 构造函数
    constructor(message: string) {
        super(message)
        this.greeting2 = message
    }
    setGreeting(message: string) {
        this.greeting = message
    }
    getTimer() {
        return this.timer
    }
    setTimer(timer: Date) {
        this.timer = timer
    }
}
const greeter2 = new Greeter2("world")
greeter2.setGreeting('Amercia')
greeter2.setColor('red')
greeter2.setTimer(new Date('2018-03-12'))
console.log(greeter2.greet())
console.log(greeter2.getColor())
console.log(greeter2.getTimer())

// 抽象类
abstract class Department {
    // readonly只读属性只能在声明和构造函数内赋值
    private readonly DepartmentName: string
    constructor(public name: string) {
        this.DepartmentName = name
    }
    printName(): void {
        console.log('Department name: ' + this.DepartmentName)
    }
    abstract printMeeting(): void // 必须在派生类中实现
}

class AccountingDepartment extends Department {
    constructor() {
        super('Accounting and Auditing') // 在派生类的构造函数中必须调用 super()
    }
    printMeeting(): void {
        console.log('The Accounting Department meets each Monday at 10am.')
    }
    generateReports(): void {
        console.log('Generating accounting reports...')
    }
}
const department = new AccountingDepartment() // 允许对一个抽象子类进行实例化和赋值
department.printName()
department.generateReports()


// Mixins
// 混入操作函数
function applyMixins(derivedCtor: any, baseCtors: any[]) {
    baseCtors.forEach(baseCtor => {
        Object.getOwnPropertyNames(baseCtor.prototype).forEach(name => {
            derivedCtor.prototype[name] = baseCtor.prototype[name]
        })
    })
}

// Disposable Mixin
class Disposable {
    isDisposed: boolean
    dispose() {
        this.isDisposed = true
    }

}
// Activatable Mixin
class Activatable {
    isActive: boolean
    activate() {
        this.isActive = true
    }
    deactivate() {
        this.isActive = false
    }
}
class SmartObject implements Disposable, Activatable {
    // Disposable
    isDisposed: boolean = false
    dispose: () => void
    // Activatable
    isActive: boolean = false
    activate: () => void
    deactivate: () => void
}

applyMixins(SmartObject, [Disposable, Activatable])
const smartObj = new SmartObject()
console.log(smartObj)


// 模块
// import
import test2 from './test2.ts'
import { fun } from './test2.ts'
import * as test2All from './test2.ts'

// 命名空间
namespace Validation {
    export interface StringValidator {
        isAcceptable(s: string): boolean
    }
    const lettersRegexp = /^[A-Za-z]+$/
    const numberRegexp = /^[0-9]+$/

    export class LettersOnlyValidator implements StringValidator {
        isAcceptable(s: string) {
            return lettersRegexp.test(s)
        }
    }

    export class ZipCodeValidator implements StringValidator {
        isAcceptable(s: string) {
            return s.length === 5 && numberRegexp.test(s)
        }
    }
}

const strings: string[] = ["Hello", "98052", "101"]
const validators: { [s: string]: Validation.StringValidator } = {}
validators["ZIP code"] = new Validation.ZipCodeValidator()
validators["Letters only"] = new Validation.LettersOnlyValidator()
console.log('ZIP code：', validators["ZIP code"].isAcceptable(strings[0]))
console.log('Letters only：', validators["Letters only"].isAcceptable(strings[0]))